﻿///-----------------------------------------------------------------------
/// <copyright file="Maintenance.cs" company="FactSet Research Systems, Inc.">
///     Copyright © FactSet Research Systems, Inc.  All rights reserved 2012.
/// </copyright>
/// <author>Jonathan K. Barez</author>
///-----------------------------------------------------------------------

namespace HousholdISv2.ViewModel.Maintenance
{
    using System;
    using System.Collections.ObjectModel;
    using System.Globalization;
    using System.Linq;
    using System.Transactions;
    using System.Windows;
    using System.Windows.Controls;
    using Core;
    using DataRepository;
    using GalaSoft.MvvmLight.Messaging;
    using MVVMCore;
    using MVVMCore.ViewModel;
    using MVVMCore.ViewModel.Details;

    public class ExpenseTypesViewModel : CollectionViewModel<ViewModelBase>, IHasItemCollection
    {
        #region Fields

        private Action cancelAction;

        #endregion Fields

        #region Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="ExpenseTypesViewModel"/> class.
        /// </summary>
        public ExpenseTypesViewModel()
        {
            this.Details = new ObservableCollection<ViewModelBase>(); 
        }

        #endregion Constructors

        #region Properties

        public string DisplayName
        {
            get { return "Expense Types"; }
        }

        public double ListMinWidth
        {
            get { return GetValue(() => ListMinWidth, 150); }
            set { SetValue(() => ListMinWidth, value); }
        }

        public double DetlMinWidth
        {
            get { return GetValue(() => DetlMinWidth, 250); }
            set { SetValue(() => DetlMinWidth, value); }
        }

        public bool IsSelected
        {
            get { return GetValue(() => IsSelected); }
            set { SetValue(() => IsSelected, value); }
        }

        public ListViewViewModel<ExpenseType> List
        {
            get { return GetValue(() => this.List) ?? this.InitializeList(); }
            set { SetValue(() => this.List, value); }
        }

        public ObservableCollection<ViewModelBase> Details
        {
            get { return GetValue(() => this.Details); }
            set { SetValue(() => this.Details, value); }
        }

        public bool IsInSelectionMode
        {
            get { return GetValue(() => this.IsInSelectionMode, true); }
            set { SetValue(() => this.IsInSelectionMode, value); }
        }

        public CommandCollectionViewModel CommandCollection
        {
            get { return GetValue(() => this.CommandCollection) ?? this.InitializeCommandCollection(); }
            set { SetValue(() => this.CommandCollection, value); }
        }

        #region Commands

        private CommandViewModel NewCommand
        {
            get { return GetValue(() => this.NewCommand) ?? this.InitializeNewCommand(); }
            set { SetValue(() => this.NewCommand, value); }
        }

        private CommandViewModel EditCommand
        {
            get { return GetValue(() => this.EditCommand) ?? this.InitializeEditCommand(); }
            set { SetValue(() => this.EditCommand, value); }
        }

        private CommandViewModel DeleteCommand
        {
            get { return GetValue(() => this.DeleteCommand) ?? this.InitializeDeleteCommand(); }
            set { SetValue(() => this.DeleteCommand, value); }
        }

        private CommandViewModel SaveCommand
        {
            get { return GetValue(() => this.SaveCommand) ?? this.InitializeSaveCommand(); }
            set { SetValue(() => this.SaveCommand, value); }
        }

        private CommandViewModel CancelCommand
        {
            get { return GetValue(() => this.CancelCommand) ?? this.InitializeCancelCommand(); }
            set { SetValue(() => this.CancelCommand, value); }
        }

        #endregion Commands

        #endregion Properties

        #region Methods

        public void RefreshList()
        {
            this.IsInSelectionMode = true;
            Refresh(this.List);
        }

        protected override ObservableCollection<ViewModelBase> InitializeItems()
        {
            return
                new ObservableCollection<ViewModelBase>
                    {
                        this.List,
                    };
        }

        private static void Refresh(ListViewViewModel<ListViewItemViewModel<ExpenseType>, ExpenseType> list)
        {
            var last = list.SelectedData;
            list.ClearItems();
            using (var dc = Context.GetContextInstance())
            {
                foreach (var et in dc.ExpenseTypes)
                {
                    list.Add(et, string.Format("{0}{1}", et.Description, (et.PositiveExpense != null ? " (+)" : string.Empty)));
                }
            }

            if (last == null)
            {
                return;
            }

            var found = list.SingleOrDefault(item => item.Data.Id == last.Id);
            if (found != null &&
                !found.IsSelected)
            {
                found.IsSelected = true;
            }
        }

        private ListViewViewModel<ExpenseType> InitializeList()
        {
            var list = new ListViewViewModel<ExpenseType>();
            list.HighlightedForeground = list.Foreground;
            list.SelectionChanged += this.ListSelectionChanged;
            Refresh(list);
            this.ResetCommands();
            return this.List = list;
        }

        private void ListSelectionChanged(object sender, SelectionChangedEventArgs<ListViewItemViewModel<ExpenseType>> e)
        {
            this.ClearDetails();
            if (e.Current == null)
            {
                return;
            }

            var data = e.Current.Data;
            var detail =
                new RecordDetailViewModel(
                    new TextBoxViewModel
                        {
                            Caption = "Id:",
                            Value =
                                data.Id == 0
                                    ? string.Empty
                                    : data.Id.ToString(CultureInfo.InvariantCulture),
                            IsReadOnly = true
                        },
                    new TextBoxViewModel
                        {
                            Caption = "Description:",
                            Value = data.Description,
                            IsReadOnly = true
                        },
                    new CheckBoxViewModel
                        {
                            Caption = "Positive Expense:",
                            Value = data.PositiveExpense != null,
                            IsReadOnly = true
                        });
            detail.IsValidChecker =
                () =>
                    {
                        var desc = detail.FindCaptionedModel<TextBoxViewModel>("Description");
                        if (!string.IsNullOrEmpty(desc.Value))
                        {
                            if (this.List.SelectedData != null)
                            {
                                if (!string.Equals(desc.Value,
                                                   this.List.SelectedData.Description,
                                                   StringComparison.InvariantCulture))
                                {
                                    return true;
                                }
                            }

                            if (this.List.SelectedData != null)
                            {
                                var posValue = detail.FindCaptionedModel<CheckBoxViewModel>("Positive Expense").Value;
                                if (posValue != (this.List.SelectedData.PositiveExpense != null))
                                {
                                    return true;
                                }
                            }
                        }

                        return false;
                    };
            this.Details.Add(detail);
            this.ResetCommands();
        }

        private CommandCollectionViewModel InitializeCommandCollection()
        {
            var ccvm =
                new CommandCollectionViewModel
                {
                    Orientation = Orientation.Vertical,
                    VerticalAlignment = VerticalAlignment.Top,
                    HorizontalAlignment = HorizontalAlignment.Stretch,
                    CommandSpacing = 5,
                };
            ccvm.AddRange(
                this.NewCommand,
                this.EditCommand,
                this.DeleteCommand,
                this.SaveCommand,
                this.CancelCommand);
            return this.CommandCollection = ccvm;
        }

        #region Commands

        private CommandViewModel InitializeNewCommand()
        {
            var cvm = new CommandViewModel("New", param => this.DoCreateNew());
            return this.NewCommand = cvm;
        }

        private CommandViewModel InitializeEditCommand()
        {
            var cvm =
                new CommandViewModel(
                    "Edit",
                    param => this.DoEdit(),
                    param => this.List.SelectedData != null);
            return this.EditCommand = cvm;
        }

        private CommandViewModel InitializeDeleteCommand()
        {
            var cvm =
                new CommandViewModel(
                    "Delete",
                    param => this.DoDelete(),
                    param => this.List.SelectedData != null);
            return this.DeleteCommand = cvm;
        }

        private CommandViewModel InitializeSaveCommand()
        {
            var cvm = new CommandViewModel(
                "Save",
                param => this.DoSave(),
                param =>
                    {
                        var maint = this.Details.OfType<RecordDetailViewModel>().FirstOrDefault();
                        return maint != null && maint.IsValid;
                    });
            return this.SaveCommand = cvm;
        }

        private CommandViewModel InitializeCancelCommand()
        {
            var cvm = new CommandViewModel("Cancel", param => this.DoCancel());
            return this.CancelCommand = cvm;
        }

        #endregion Commands

        private  void DoCreateNew()
        {
            this.ClearDetails();
            var last = this.List.SelectedItem;

            var newType = new ExpenseType {Description = "<New Expense Type>"};
            this.List.RaiseSelectionChangedEvent = false;
            var lvivm = this.List.Add(newType, newType.Description);
            lvivm.IsSelected = true;
            this.List.RaiseSelectionChangedEvent = true;
            this.List.InvokeSelectionChanged();
            this.IsInSelectionMode = false;

            var detail = this.Details.OfType<RecordDetailViewModel>().First();
            detail.FindCaptionedModel("Description").IsReadOnly = false;
            detail.FindCaptionedModel("Positive Expense").IsReadOnly = false;
            this.ResetCommands();

            this.cancelAction =
                () =>
                {
                    this.IsInSelectionMode = true;
                    this.List.Remove(lvivm);
                    if (last == null)
                    {
                        this.ResetCommands();
                        return;
                    }

                    this.List.RaiseSelectionChangedEvent = false;
                    last.IsSelected = true;
                    this.List.RaiseSelectionChangedEvent = true;
                    this.List.InvokeSelectionChanged();
                };
        }

        private void DoEdit()
        {
            this.IsInSelectionMode = false;
            var detail = this.Details.OfType<RecordDetailViewModel>().First();
            detail.FindCaptionedModel("Description").IsReadOnly = false;
            detail.FindCaptionedModel("Positive Expense").IsReadOnly = false;
            this.ResetCommands();

            this.cancelAction =
                () =>
                    {
                        this.IsInSelectionMode = true;
                        this.List.InvokeSelectionChanged();
                    };
        }

        private void DoDelete()
        {
            Messenger.Send(
                new DialogMessage(
                    "Not yet implemented!",
                    delegate { })
                {
                    Button = MessageBoxButton.OK,
                    Caption = "Delete",
                    Icon = MessageBoxImage.Information
                });
        }

        private void DoSave()
        {
            var detail = this.Details.OfType<RecordDetailViewModel>().First();
            var data = this.List.SelectedData;

            data.Description = detail.FindCaptionedModel<TextBoxViewModel>("Description").Value;
            using (var scope = new TransactionScope())
            {
                using (var dc = Context.GetContextInstance())
                {
                    if (data.Id == 0)
                    {
                        dc.AddToExpenseTypes(data);
                    }
                    else
                    {
                        var found = dc.ExpenseTypes.Single(item => item.Id == data.Id);
                        found.Description = data.Description;
                        data = found;
                    }

                    if (detail.FindCaptionedModel<CheckBoxViewModel>("Positive Expense").Value)
                    {
                        if (data.PositiveExpense == null)
                        {
                            data.PositiveExpense = new PositiveExpense {ExpenseType = data};
                        }
                    }else
                    {
                        if (data.PositiveExpense != null)
                        {
                            data.PositiveExpense = null;
                        }
                    }

                    dc.SaveChanges();
                }
               
                scope.Complete();
            }

            this.RefreshList();
        }

        private void DoCancel()
        {
            if (this.cancelAction == null)
            {
                return;
            }

            this.cancelAction();
            this.cancelAction = null;
        }

        private void ClearDetails()
        {
            while (this.Details.Count > 0)
            {
                this.RemoveLastDetail();
            }
        }

        private void RemoveLastDetail()
        {
            using (var last = this.Details.Last())
            {
                this.Details.Remove(last);
            }
        }

        private void ResetCommands()
        {
            var detail = this.Details.OfType<RecordDetailViewModel>().FirstOrDefault();
            SetVisibility(
                detail == null || this.IsInSelectionMode ? Visibility.Visible : Visibility.Collapsed,
                this.NewCommand);

            SetVisibility(
                this.IsInSelectionMode ? Visibility.Visible : Visibility.Collapsed,
                this.EditCommand,
                this.DeleteCommand);

            SetVisibility(
                !this.IsInSelectionMode ? Visibility.Visible : Visibility.Collapsed,
                this.SaveCommand,
                this.CancelCommand);
        }

        private static void SetVisibility(Visibility visibility, params CommandViewModel[] commands)
        {
            commands.ForEach(cmd => cmd.Visibility = visibility);
        }

        #endregion Methods
    }
}
